package com.xjrsoft.module.base.service.impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.core.constant.RedisKeyConstants;
import com.xjrsoft.core.secure.XjrUser;
import com.xjrsoft.core.secure.utils.SecureUtil;
import com.xjrsoft.core.tool.node.ForestNodeMerger;
import com.xjrsoft.core.tool.utils.*;
import com.xjrsoft.module.base.entity.*;
import com.xjrsoft.module.base.mapper.XjrBaseModuleMapper;
import com.xjrsoft.module.base.service.*;
import com.xjrsoft.module.base.utils.ModuleUtils;
import com.xjrsoft.module.base.vo.*;
import com.xjrsoft.module.buildCode.dto.BaseInfoDto;
import com.xjrsoft.module.buildCode.dto.CodeSchemaDto;
import com.xjrsoft.module.buildCode.dto.ColDataDto;
import com.xjrsoft.module.buildCode.dto.ModuleDataDto;
import com.xjrsoft.module.buildCode.props.GlobalConfigProperties;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author jobob
 * @since 2020-10-27
 */
@Service
@AllArgsConstructor
public class XjrBaseModuleServiceImpl extends ServiceImpl<XjrBaseModuleMapper, XjrBaseModule> implements IXjrBaseModuleService {

    private IXjrBaseRoleService roleService;

    private IXjrBaseModuleButtonService moduleButtonService;

    private IXjrBaseModuleColumnService moduleColumnService;

    private IXjrBaseModuleFormService moduleFormService;

    public GlobalConfigProperties globalConfigProperties;

    private IXjrBaseSubsystemService subsystemService;

    private RedisUtil redisUtil;

    @Override
    public List<XjrBaseModule> getAuthModuleForCurrentUser() {
        if (!SecureUtil.isAdminUser()) {
            return getAuthModuleForObject(SecureUtil.getUserId(), 2);
        } else {
            return getActiveModuleList();
        }
    }


    @Override
    public List<XjrBaseModule> getAuthModuleForObject(String objectId, Integer objectType) {
        String userId = StringPool.EMPTY;
        List<String> roleIds = new ArrayList<>();
        if (objectType == 1) {
            roleIds.add(objectId);
        } else {
            userId = objectId;
           roleIds.addAll(SecureUtil.getRoleIdList());
        }
        return this.baseMapper.getModuleOfAuth(userId, roleIds);
    }

    @Override
    public List<ModuleOtherVo> getSubAuthorizations() {
        String userId = SecureUtil.getUserId();
        if (StringUtil.isEmpty(userId)) {
            return null;
        }
        boolean isAdminUser = SecureUtil.isAdminUser();

        List<String> authCode = new ArrayList<>();
        // 查询用户的角色
        String[] roleIdArray = Func.toStrArray(SecureUtil.getUser().getRoleId());
        List<String> moduleIdList = baseMapper.getModuleIdsOfAuth(isAdminUser, 2, userId);
        if (!isAdminUser && roleIdArray != null && roleIdArray.length > 0) {
            moduleIdList.addAll(baseMapper.getModuleIdsOfAuth(false, 1, roleIdArray));
        }
        Map<String, ModuleOtherVo> moduleOtherVoMap = new HashMap<>(moduleIdList.size());

        if (CollectionUtil.isNotEmpty(moduleIdList)) {
            // 查询权限按钮


            // 用户
            List<XjrBaseModuleButton> userBtnList = this.getAuthButtonForCurUser(moduleIdList);
            ModuleUtils.buildAuthBtnVo(userBtnList, moduleOtherVoMap,authCode);

            // 查询权限列表字段
            List<XjrBaseModuleColumn> userColList = this.getAuthColumnForCurUser(moduleIdList);
            ModuleUtils.buildAuthColVo(userColList, moduleOtherVoMap);
            // 查询权限表单字段
            List<XjrBaseModuleForm> userFormList = this.getAuthFormForCurUser(moduleIdList);
            ModuleUtils.buildAuthFormVo(userFormList, moduleOtherVoMap);
//            if (!isAdminUser && roleIdArray != null && roleIdArray.length > 0) {
//                // 角色
//                List<XjrBaseModuleButton> roleBtnList = baseMapper.getModuleBtnOfAuth(false, moduleIdList, 1, roleIdArray);
//                ModuleUtils.buildAuthBtnVo(roleBtnList, moduleOtherVoMap);
//
//                List<XjrBaseModuleColumn> roleColList = baseMapper.getModuleColOfAuth(false, moduleIdList, 1, roleIdArray);
//                ModuleUtils.buildAuthColVo(roleColList, moduleOtherVoMap);
//
//                List<XjrBaseModuleForm> roleFormList = baseMapper.getModuleFormOfAuth(false, moduleIdList, 1, roleIdArray);
//                ModuleUtils.buildAuthFormVo(roleFormList, moduleOtherVoMap);
//            }
        }
        List<ModuleOtherVo> resultList = new ArrayList<>(moduleOtherVoMap.size());
        for (Map.Entry<String, ModuleOtherVo> entry : moduleOtherVoMap.entrySet()) {
            ModuleOtherVo value = entry.getValue();
            value.setModuleId(entry.getKey());
            resultList.add(value);
        }
        SaSession tokenSession = StpUtil.getTokenSession();
        // 将用户的权限存入到redis
        tokenSession.set(RedisKeyConstants.CACHE_AUTH_CODE_KEY,authCode);
        return resultList;
    }

    @Override
    public boolean saveModule(String moduleId, CodeSchemaDto codeSchemaDto) {
        ModuleDataDto moduleDataDto = codeSchemaDto.getModuleDataDto();
        BaseInfoDto baseInfoDto = codeSchemaDto.getBaseInfoDto();
        XjrBaseModule module = BeanUtil.copy(moduleDataDto, XjrBaseModule.class);
        module.setDeleteMark(0);
        module.setEnabledMark(1);
        module.setIsMenu(1);
        module.setCreateDate(LocalDateTime.now());
        module.setTarget("iframe");
        module.setComponent(baseInfoDto.getFontDirectory() + "/" + baseInfoDto.getName() + "List");
        module.setModuleId(moduleId);
        module.setUrlAddress("/" + StringUtils.lowerCase(baseInfoDto.getName()));
        if (StringUtil.isEmpty(module.getParentId())) {
            module.setParentId("0");
        }
        ColDataDto colDataDto = codeSchemaDto.getColDataDto();
        // 按钮
        List<Map<String, Object>> buttonList = colDataDto.getButtonList();
        List<XjrBaseModuleButton> buttonEntities = new ArrayList<>(buttonList.size());
        if (CollectionUtil.isNotEmpty(buttonList)) {
            for (Map<String, Object> button : buttonList) {
                if (!MapUtils.getBoolean(button, "checked", false)) {
                    continue;
                }
                XjrBaseModuleButton buttonEntity = new XjrBaseModuleButton();
                buttonEntity.setModuleId(moduleId);
                buttonEntity.setParentId(StringPool.ZERO);
                buttonEntity.setEnCode(baseInfoDto.getName() + ":" + MapUtils.getString(button, "val"));
                buttonEntity.setFullName(MapUtils.getString(button, "name"));
                buttonEntity.setIcon(MapUtils.getString(button, "icon"));
                buttonEntities.add(buttonEntity);
            }
        }
        moduleButtonService.saveBatch(buttonEntities);

        // 列表字段
        List<Map<String, Object>> columnList = colDataDto.getColumnList();
        List<XjrBaseModuleColumn> columnEntities = new ArrayList<>(columnList.size());
        if (CollectionUtil.isNotEmpty(columnList)) {
            for (Map<String, Object> column : columnList) {
                XjrBaseModuleColumn columnEntity = new XjrBaseModuleColumn();
                columnEntity.setFullName(MapUtils.getString(column, "fieldName"));
                columnEntity.setEnCode(MapUtils.getString(column, "bindColumn"));
                columnEntity.setModuleId(moduleId);
                columnEntity.setParentId(StringPool.ZERO);
                columnEntity.setSortCode(MapUtils.getInteger(column, "$index"));
                columnEntities.add(columnEntity);
            }
        }
        moduleColumnService.saveBatch(columnEntities);

        // 表单字段
        List<Map<String, Object>> formDataDtoList = codeSchemaDto.getFormDataDtoList();
        List<XjrBaseModuleForm> formList = ModuleUtils.buildFormEntities(moduleId, formDataDtoList);
        moduleFormService.saveBatch(formList);

        return this.save(module);
    }

    private XjrBaseModuleForm buildFormField(String moduleId, Map<String, Object> config) {
        XjrBaseModuleForm form = new XjrBaseModuleForm();
        form.setModuleId(moduleId);
        String bindTableField = MapUtils.getString(config, "bindTableField");
        if (StringUtil.isNotBlank(bindTableField)) {
            form.setEnCode(bindTableField);
            form.setFullName(MapUtils.getString(config, "label"));
            Boolean required = MapUtils.getBoolean(config, "required");
            form.setIsRequired(required != null && required ? 1 : 0);
        } else {
            form.setEnCode(MapUtils.getString(config, "bindTable"));
        }
        return form;
    }

    @Override
    public List<ModuleButtonVo> getButtonsByModuleId(String moduleId) {
        return moduleButtonService.getButtonsByModuleId(moduleId);
    }

    @Override
    public List<ModuleColumnVo> getColumnsByModuleId(String moduleId) {
        return moduleColumnService.getColumnsByModuleId(moduleId);
    }

    @Override
    public List<ModuleFormVo> getFormsByModuleId(String moduleId) {
        return moduleFormService.getFormByModuleId(moduleId);
    }

    @Override
    @Transactional
    public boolean addModule(XjrBaseModule module, List<XjrBaseModuleButton> buttonList, List<XjrBaseModuleColumn> columnList, List<XjrBaseModuleForm> formList) throws Exception {
        //判断上级菜单是否为功能菜单
        XjrBaseModule xjrBaseModule = this.getOne(Wrappers.<XjrBaseModule>query().lambda().eq(XjrBaseModule::getModuleId, module.getParentId()));
        if (xjrBaseModule != null && "iframe".equals(xjrBaseModule.getTarget())) {
            throw new Exception("上级菜单不能为功能菜单!!!");
        }
        if (module.getIsMenu() == null) {
            module.setIsMenu(1);
        }
        String moduleId = StringUtil.isNotBlank(module.getModuleId()) ? module.getModuleId() : IdWorker.get32UUID();
        module.setModuleId(moduleId);
        if (StringUtil.isEmpty(module.getParentId())) {
            module.setParentId(StringPool.ZERO);
        }
        if (CollectionUtil.isNotEmpty(buttonList)) {
            buttonList.forEach(button -> {
                button.setModuleId(moduleId);
                if (StringUtil.isEmpty(button.getParentId())) {
                    button.setParentId(StringPool.ZERO);
                }
            });
        }
        if (CollectionUtil.isNotEmpty(columnList)) {
            columnList.forEach(column -> {
                column.setModuleId(moduleId);
                if (StringUtil.isEmpty(column.getParentId())) {
                    column.setParentId(StringPool.ZERO);
                }
            });
        }
        if (CollectionUtil.isNotEmpty(formList)) {
            formList.forEach(form -> form.setModuleId(moduleId));
        }
        boolean isSuccess = this.save(module);
        if (isSuccess) {
            moduleButtonService.saveBatch(buttonList);
            moduleColumnService.saveBatch(columnList);
            moduleFormService.saveBatch(formList);
        }
        return isSuccess;
    }

    @Override
    public boolean updateModule(String moduleId, XjrBaseModule module, List<XjrBaseModuleButton> buttonList, List<XjrBaseModuleColumn> columnList, List<XjrBaseModuleForm> formList) throws Exception {
        //判断上级菜单是否为功能菜单
        XjrBaseModule xjrBaseModule = this.getOne(Wrappers.<XjrBaseModule>query().lambda().eq(XjrBaseModule::getModuleId, module.getParentId()));
        if (xjrBaseModule != null && "iframe".equals(xjrBaseModule.getTarget())) {
            throw new Exception("上级菜单不能为功能菜单!!!");
        }
        module.setModuleId(moduleId);
        if (CollectionUtil.isNotEmpty(buttonList)) {
            buttonList.forEach(button -> button.setModuleId(moduleId));
        }
        if (CollectionUtil.isNotEmpty(columnList)) {
            columnList.forEach(column -> column.setModuleId(moduleId));
        }
        if (CollectionUtil.isNotEmpty(formList)) {
            formList.forEach(form -> form.setModuleId(moduleId));
        }
        boolean isSuccess = this.updateById(module);
        if (isSuccess) {
            moduleButtonService.remove(Wrappers.<XjrBaseModuleButton>query().lambda().eq(XjrBaseModuleButton::getModuleId, moduleId));
            moduleButtonService.saveBatch(buttonList);

            moduleColumnService.remove(Wrappers.<XjrBaseModuleColumn>query().lambda().eq(XjrBaseModuleColumn::getModuleId, moduleId));
            moduleColumnService.saveBatch(columnList);

            moduleFormService.remove(Wrappers.<XjrBaseModuleForm>query().lambda().eq(XjrBaseModuleForm::getModuleId, moduleId));
            moduleFormService.saveBatch(formList);
        }
        return isSuccess;
    }

    @Override
    public List<XjrBaseModule> getModulesByParentId(String moduleId) {
        return this.list(Wrappers.<XjrBaseModule>query().lambda().eq(XjrBaseModule::getParentId, moduleId));
    }

    public List<XjrBaseModule> getActiveModuleList() {
        return this.list(Wrappers.<XjrBaseModule>query().lambda().eq(XjrBaseModule::getDeleteMark, 0)
                .eq(XjrBaseModule::getEnabledMark, 1)
                .eq(XjrBaseModule::getIsMenu, 1)
                .orderByAsc(XjrBaseModule::getSortCode));
    }

    public List<ModuleVo> getTransModuleList() {
        Boolean enabledSubSystem = globalConfigProperties.getEnabled_subSystem();
        return this.baseMapper.getTransModuleList(enabledSubSystem);
    }

    @Override
    public Map<String, SystemModuleTreeVo> getAllAuthModuleTree() {
        //        List<XjrBaseModule> moduleList = moduleService.list(Wrappers.<XjrBaseModule>query().lambda()
//                .eq(!this.globalConfigProperties.getEnabled_subSystem(), XjrBaseModule::getSubSystemId, "0")
//                .eq(XjrBaseModule::getIsMenu, 1)
//                .eq(XjrBaseModule::getEnabledMark, true).orderByAsc(XjrBaseModule::getSortCode));
        // 获取当前用户授权的菜单
        List<XjrBaseModule> moduleList = this.getAuthModuleForCurrentUser();
        List<XjrBaseSubsystem> subsystemList = null;
        if (this.globalConfigProperties.getEnabled_subSystem()) {
            if (!SecureUtil.isAdminUser()) {
                subsystemList = subsystemService.selectAuthList(SecureUtil.getUserId());
            } else {
                subsystemList = subsystemService.getActiveList();
            }
        }
        List<ModuleVo> moduleVoList = BeanUtil.copyList(moduleList, ModuleVo.class);
        List<String> moduleIdList = new ArrayList<>();
        moduleVoList.forEach(moduleVo ->{
            if (StringUtil.equalsIgnoreCase(moduleVo.getTarget(), "iframe")) {
                moduleIdList.add(moduleVo.getModuleId());
            }
        });
        Map<String, SystemModuleTreeVo> resultMap = new HashMap<>(4);
        // 查询按钮
        List<XjrBaseModuleButton> moduleButtonList = getAuthButtonForCurUser(moduleIdList);
        List<ModuleVo> btnModuleVoList = ModuleUtils.buildSubModuleTree(moduleVoList, moduleButtonList, ModuleButtonVo.class);
        SystemModuleTreeVo systemBtnModuleTreeVo = ModuleUtils.buildSystemModuleVo(btnModuleVoList, subsystemList);
        resultMap.put("buttonList", systemBtnModuleTreeVo);

        // 查询列表字段
        List<XjrBaseModuleColumn> moduleColumnList = this.getAuthColumnForCurUser(moduleIdList);
        List<ModuleVo> colModuleVoList = ModuleUtils.buildSubModuleTree(moduleVoList, moduleColumnList, ModuleColumnVo.class);
        SystemModuleTreeVo systemColModuleTreeVo = ModuleUtils.buildSystemModuleVo(colModuleVoList, subsystemList);
        resultMap.put("columnList", systemColModuleTreeVo);

        // 查询表单字段
        List<XjrBaseModuleForm> moduleFormList = getAuthFormForCurUser(moduleIdList);
        List<ModuleVo> formModuleVoList = ModuleUtils.buildSubModuleTree(moduleVoList, moduleFormList, ModuleFormVo.class);
        SystemModuleTreeVo systemFormModuleTreeVo = ModuleUtils.buildSystemModuleVo(formModuleVoList, subsystemList);
        resultMap.put("formList", systemFormModuleTreeVo);

        List<ModuleVo> moduleVoTreeList = ForestNodeMerger.merge(moduleVoList);
        SystemModuleTreeVo systemModuleTreeVo = ModuleUtils.buildSystemModuleVo(moduleVoTreeList, subsystemList);
        resultMap.put("moduleList", systemModuleTreeVo);
        return resultMap;
    }

    private List<XjrBaseModuleButton> getAuthButtonForCurUser(List<String> moduleIdList) {
        XjrUser user = SecureUtil.getUser();
        if (user.isAdminUser()) {
            return moduleButtonService.list(Wrappers.<XjrBaseModuleButton>query().lambda().in(XjrBaseModuleButton::getModuleId, moduleIdList));
        } else {
            return this.baseMapper.getModuleBtnOfAuth(moduleIdList, user.getUserId(), Arrays.asList(StringUtils.split(user.getRoleId(), StringPool.COMMA)));
        }
    }

    private List<XjrBaseModuleColumn> getAuthColumnForCurUser(List<String> moduleIdList) {
        XjrUser user = SecureUtil.getUser();
        if (user.isAdminUser()) {
            return moduleColumnService.list(Wrappers.<XjrBaseModuleColumn>query().lambda().in(XjrBaseModuleColumn::getModuleId, moduleIdList));
        } else {
            return this.baseMapper.getModuleColOfAuth(moduleIdList, user.getUserId(), Arrays.asList(StringUtils.split(user.getRoleId(), StringPool.COMMA)));
        }
    }

    private List<XjrBaseModuleForm> getAuthFormForCurUser(List<String> moduleIdList) {
        XjrUser user = SecureUtil.getUser();
        if (user.isAdminUser()) {
            return moduleFormService.list(Wrappers.<XjrBaseModuleForm>query().lambda().in(XjrBaseModuleForm::getModuleId, moduleIdList));
        } else {
            return this.baseMapper.getModuleFormOfAuth(moduleIdList, user.getUserId(), Arrays.asList(StringUtils.split(user.getRoleId(), StringPool.COMMA)));
        }
    }
}
